#include <iostream>
#include <string>
#include <algorithm>

#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>

#include "remote_calculate.grpc.pb.h"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerReader;
using grpc::ServerReaderWriter;
using grpc::ServerWriter;
using grpc::Status;

using calculator::Calculator;
using calculator::AddRequest;
using calculator::AddResponse;
using calculator::SumRequest;
using calculator::SumResponse;
using calculator::RankRequest;
using calculator::RankResponse;
using calculator::SortRequest;
using calculator::SortResponse;

class RemoteCalculatorImpl final : public Calculator::Service {
    Status Add(ServerContext* context, const AddRequest* request, AddResponse* response) {
        int64_t result = static_cast<int64_t>(request->a()) + request->b();
        response->set_result(result);
        return Status::OK;
    }

    Status Sum(ServerContext* context, ServerReader<SumRequest>* reader, SumResponse* response) {
        int64_t result = 0;
        SumRequest msg;
        while (reader->Read(&msg)) {    // 从流中读取一个个请求对象
            result += static_cast<int64_t>(msg.num());
        }
        response->set_sum(result);
        return Status::OK;
    }

    Status Rank(ServerContext* context, const RankRequest* request, ServerWriter<RankResponse>* writer) {
        int32_t digit = request->digit();
        RankResponse response;
        for (int32_t i = 1; i <= digit; i++) {
            response.set_digit(i);
            writer->Write(response);
        }
        return Status::OK;
    }

    Status Sort(ServerContext* context, ServerReaderWriter<SortResponse, SortRequest>* stream) {
        std::vector<int32_t> digits;
        SortRequest request;
        while (stream->Read(&request))
        {
            digits.emplace_back(request.num());
        }
        std::sort(digits.begin(), digits.end());
        SortResponse response;
        for (auto digit : digits) {
            response.set_num(digit);
            stream->Write(response);
        }
        return Status::OK;
    }
};

void RunServer() {
    std::string server_address("0.0.0.0:43089");
    RemoteCalculatorImpl service;

    grpc::EnableDefaultHealthCheckService(true);
    grpc::reflection::InitProtoReflectionServerBuilderPlugin();
    ServerBuilder builder;

    //  添加监听端口
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());

    // 注册服务
    builder.RegisterService(&service);

    std::unique_ptr<Server> server(builder.BuildAndStart());
    std::cout << "Server listening on " << server_address << std::endl;

    server->Wait();
}

int main(int argc, char* argv[]) {
    RunServer();
    return 0;
}